//! 左值是左面，可取地址，右值是右面，不可取地址。
//
// # 左值（lvalue）
// 左值是指表达式结束后依然存在的持久对象，并且其地址可以被获取。左值通常表示一个具有确定存储位置的对象，因此它们可以被赋值。几乎所有的变量都是左值（除了非常特殊的类型，如临时对象）。

// # 右值（rvalue）
// 右值是指表达式结束后不再存在的临时对象，或者其值可以被“移动”的对象。右值可以是字面常量、临时对象或表达式的结果，并且它们通常没有存储位置（或者其存储位置在表达式结束后不再有效）。在C++11之前，右值也被称为“纯右值”（prvalue），但在C++11及以后，右值被进一步细分为“纯右值”和“将亡值”（xvalue）。

// * 纯右值（prvalue）：不持有对象身份的表达式的值，如字面常量、非引用返回的临时对象等。
// * 将亡值（xvalue）：即将被销毁的对象，如std::move的返回值、T&&类型的函数返回值等。

#include <iostream>

using namespace std;

/**
 * @brief 接受右值引用的函数举例
 *
 * @param rval
 */
void foo(int &&rval);

class MyString {
public:
  MyString(const std::string &s) : data(new std::string(s)) {}
  MyString(MyString &&other) noexcept : data(other.data) {
    other.data = nullptr; // 移动语义：接管other的资源，并释放other的资源
  }
  ~MyString() { delete data; }

  void print() const {
    if (data) {
      std::cout << *data << std::endl;
    }
  }

private:
  std::string *data;
};

int main() {
  {
    int x = 10;   // x是左值, 10是右值
    int &y = x;   // x是左值，y是右值引用，引用了x的地址
    int &&z = 20; // 右值引用
    int &&x_rv = std::move(x); // 右值引用，绑定到x的右值上
    std::cout << "x = " << x << std::endl;
    std::cout << "y = " << y << std::endl;
    std::cout << "z = " << z << std::endl;
    std::cout << "x_rv = " << x_rv << std::endl;
  }
  {
    int x = 20;
    foo(10); // 10 是一个右值，它被绑定到右值引用 rval 上
    foo(std::move(x)); // 移动语义返回的是右值，它被绑定到右值引用 rval 上
    cout << "moved int x = " << x << endl; // x没有被移动
  }
  {
    MyString s1("Hello");
    MyString s2(std::move(s1)); // 使用右值引用和移动语义构造s2
    // 此时s1的data成员已经被置为nullptr，s2接管了s1原本的资源
    // ...
    // 检查s1的状态
    s2.print(); // 输出 "Hello"
    s1.print(); //  不输出任何东西，因为s1已经被销毁，但s1 的地址依然存在
  }
}

void foo(int &&rval) {
  // rval 是一个右值引用，它可以绑定到右值上
  cout << "rval = " << rval << endl;
}